#ifndef ROUTING_TOPO_H
#define ROUTING_TOPO_H

#include <vector>
#include "Topology.h"

using namespace std;

#ifndef VMS_H
#define VMS_H
class VM
{
public:
	int num;
	int host;
	map<int, double> flow;
	VM()
	{
		num = 0;
		host = 0;
		flow.clear();
	}
};

class vHost
{
public:
	int host;
	int slots;
	list<int> sptVms;
	vHost()
	{
		host = 0;
		slots = 0;
		sptVms.clear();
	}
};
#endif

struct Host
{
	int num;
	list<int> vms;
};

class Routing_topo : public Topology
{
private:
	map<string, double> flow;
	map<int, Host> hosts;
	map<string, double> host_flow;
	bool cons;
	bool consp;
public:
	map<string, double> capacity;
	map<string, double> host_matrix;
	map<string, vector<vector<string> > > plinks;
	map<string, map<string, double> > fijst;
	//map<string, double> load;
	map<string, double> utility;
	Routing_topo()
	{
		fijst.clear();
		flow.clear();
		hosts.clear();
		host_flow.clear();
		capacity.clear();
		plinks.clear();
		host_matrix.clear();
		//load.clear();
		cons = false;
		consp = false;
	}
	/*
	 * read vm placement
	*/
	bool rt_construct(map<int, VM> &ref_vms)
	{
		int total = ref_vms.size();
		map<int, VM>::iterator i;
		for (i = ref_vms.begin(); i != ref_vms.end(); i++)
		{
			int vm, host;
			vm = (*i).second.num;
			host = (*i).second.host;
			if (hosts.find(host) == hosts.end())
			{
				Host newhost;
				newhost.num = host;
				newhost.vms.push_back(vm);
				hosts[host] = newhost;
			}
			else
			{
				hosts[host].vms.push_back(vm);
			}
		}
		return true;
	}
	bool place(int vm, int host)
	{
		map<int, Host>::iterator it;
		if ((it = hosts.find(host)) == hosts.end())
		{
			return false;
		}
		(*it).second.vms.push_back(vm);
		return true;
	}
	bool remove(int vm, int host)
	{
		map<int, Host>::iterator it;
		list<int>::iterator lit;
		if ((it = hosts.find(host)) == hosts.end())
		{
			return false;
		}
		for (lit = (*it).second.vms.begin(); lit != (*it).second.vms.end(); lit++)
		{
			if ((*lit) == vm)
			{
				(*it).second.vms.erase(lit);
				return true;
			}
		}
		return false;
	}
	string xyzw(string xy, int z, int w)
	{
		string s;
		char xyzw[20000];
		sprintf(xyzw, "%s%d.%d.", xy.c_str(), z, w);
		s = xyzw;
		return s;
	}
	/*
	 * read vm matrix
	*/
	bool vm_flow_construct(string path)
	{
		FILE *input = fopen(path.c_str(), "r");
		if (!input)
		{
			cerr << "cannot open vm flow file!\n";
			//exit(1);
		}
		int vmn, total;
		fscanf(input, "%d%d", &vmn, &total);
		int i;
		for (i = 0; i < total; i++)
		{
			int vmi, vmj;
			double vflow = 0.0;
			fscanf(input, "%d%d%lf", &vmi, &vmj, &vflow);
			flow[x(vmi, vmj)] = vflow;
		}
		fclose(input);
		return true;
	}
	/*
	 * read link capacity
	*/
	bool capacity_construct(string path)
	{
		FILE *input = fopen(path.c_str(), "r");
		if (!input)
		{
			cerr << "cannot open capacity file!\n";
			//exit(1);
		}
		int total;
		fscanf(input, "%d", &total);
		int i;
		for (i = 0; i < total; i++)
		{
			int lknodei, lknodej;
			double capa = 0.0;
			fscanf(input, "%d%d%lf", &lknodei, &lknodej, &capa);
			capacity[x(lknodei, lknodej)] = capa;
			capacity[x(lknodej, lknodei)] = capa;
		}
		fclose(input);
		return true;
	}
	bool simple_ospf_route()
	{
		if (!cons) 
		{
			this->floyd_warshall();
			cout << "floyd_warshall completed...\n";
			cons = true;
		}
		/*fijst.clear();
		//load.clear();
		utility.clear();
		host_flow.clear();
		host_matrix.clear();
		map<int, Host>::iterator i, j;
		//cout << "plinks max size: " << plinks.max_size() << endl;
		//cout << "fijst max size: " << fijst.max_size() << endl;
		for (i = hosts.begin(); i != hosts.end(); i++)
			for (j = hosts.begin(); j!= hosts.end(); j++)
			{
				if ((*i).second.num == (*j).second.num)
				{
					continue;
				}
				string ij = x((*i).second.num, (*j).second.num);
				string ji = x((*j).second.num, (*i).second.num);
				//cout << "link: " << ij << "\t";
				int pi;
				if (!consp)
				{
					plinks[ij] = vector<vector<string> >();
					plinks[ij].resize(dis_path[ij].size());
					for (pi = 0; pi < dis_path[ij].size(); pi++)
					{
						string singlepath = dis_path[ij][pi];
						int psize = 0;
						int pos2 = 0;
						for (int pos = 0; pos != -1 && pos2 != -1;)
						{
							pos = singlepath.find_first_of(".");
							string sub1 = singlepath.substr(0, pos + 1);
							singlepath = singlepath.substr(pos + 1, singlepath.size() - pos - 1);
							pos2 = singlepath.find_first_of(".");
							if (pos2 == -1)
							{
								break;
							}
							if (plinks[ij][pi].size() <= psize) plinks[ij][pi].resize(psize + 1);
							plinks[ij][pi][psize] = sub1;
							plinks[ij][pi][psize] += singlepath.substr(0, pos2 + 1);
							psize++;
						}
					}
					//cout << "constructed...\n";
				}
				list<int>::iterator k, m;
				for (k = (*i).second.vms.begin(); k != (*i).second.vms.end(); k++)
				{
					for (m = (*j).second.vms.begin(); m != (*j).second.vms.end(); m++)
					{
						string km = x(*k, *m);
						double nf = 0;
						if (flow.find(km) != flow.end())
						{
							nf = flow[km];
						}
						if (nf == 0) continue;
						host_matrix[ij] += nf;
						int psize = 0;
						int path_number = plinks[ij].size();
						for (pi = 0; pi < plinks[ij].size(); pi++)
						{
							for (psize = 0; psize < plinks[ij][pi].size(); psize++)
							{
								//load[plinks[ij][pi][psize]] += nf / path_number;
								host_flow[plinks[ij][pi][psize]] += nf / path_number;
							}
						}
					}
				}
				//cout << "link completed...\n";
			}
		consp = true;
		cout << "routing complete...\n";*/
		return true;
	}
	bool distribute_ospf_route()
	{
		if (!cons) 
		{
			this->distribute_floyd_warshall();
			cout << "distribute floyd_warshall completed...\n";
			cons = true;
		}
		fijst.clear();
		//load.clear();
		utility.clear();
		host_flow.clear();
		host_matrix.clear();
		map<int, Host>::iterator i, j;
		//cout << "plinks max size: " << plinks.max_size() << endl;
		//cout << "fijst max size: " << fijst.max_size() << endl;
		for (i = hosts.begin(); i != hosts.end(); i++)
			for (j = hosts.begin(); j!= hosts.end(); j++)
			{
				if ((*i).second.num == (*j).second.num)
				{
					continue;
				}
				string ij = x((*i).second.num, (*j).second.num);
				string ji = x((*j).second.num, (*i).second.num);
				//cout << "link: " << ij << "\t";
				list<int>::iterator k, m;
				for (k = (*i).second.vms.begin(); k != (*i).second.vms.end(); k++)
				{
					for (m = (*j).second.vms.begin(); m != (*j).second.vms.end(); m++)
					{
						string km = x(*k, *m);
						double nf = 0;
						if (flow.find(km) != flow.end())
						{
							nf = flow[km];
						}
						if (nf == 0) continue;
						host_matrix[ij] += nf;
						int path_num = path_number[ij];
						vector<string>::iterator pait;
						for (pait = dis_path[ij].begin(); pait != dis_path[ij].end(); pait++)
						{
								//load[plinks[ij][pi][psize]] += nf / path_number;
								host_flow[(*pait)] += nf / path_num;
						}
					}
				}
				//cout << "link completed...\n";
			}
		consp = true;
		cout << "routing complete...\n";
		return true;
	}
	bool utility_calculate()
	{
		map<string, double>::iterator util_iter;
		string MAXi = "";
		double MAXutil = 0;
		double totalUtil = 0;
		for (util_iter = capacity.begin(); util_iter != capacity.end(); util_iter++)
		{
			string first = (*util_iter).first;
			double third = (*util_iter).second;
			double second = host_flow[first] / third;
			totalUtil += second;
			if (second > MAXutil)
			{
				MAXi = first;
				MAXutil = second;
			}
			utility[first] = second;
		}
		printf("MAX UTILITY:  %s %lf\n", MAXi.c_str(), MAXutil);
		printf("TOTAL UTILITY:  %lf\n", totalUtil);
		return true;
	}
};

#endif